package kevin.framework.basic.common.user;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.pagehelper.util.StringUtil;

import kevin.framework.basic.common.utils.IOnShutdownLogThreadPool;
import kevin.framework.basic.common.utils.OperatorRecord;
import kevin.framework.basic.common.utils.RequestInterceptor;
import kevin.framework.basic.common.utils.SysConfigParams;
import kevin.framework.basic.common.utils.UrlInfo;
import kevin.framework.basic.domain.Dict;
import kevin.framework.basic.domain.Log;
import kevin.framework.basic.service.IDictService;
import kevin.framework.basic.service.IFuncService;
import kevin.framework.basic.service.ILogService;
import kevin.framework.basic.service.IMenuService;

/**
 * @Description: 用户操作记录器
 * @author kevin.huang
 * @date 2017年3月3日 下午2:42:42
 * @version v1.0.0
 */
public class UserOperatorRecorder implements IUserOperatorRecorder {

    public final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class);

    @Resource(name = "logService")
    private ILogService logService;

    @Resource(name = "funcService")
    protected IFuncService funcService;

    @Resource(name = "menuService")
    protected IMenuService menuService;

    @Resource(name = "dictService")
    IDictService dictService;

    @Override
    public void requestAspect(LoginUser user, HttpServletRequest request) {
        // TODO Auto-generated method stub

    }

    @Override
    public OperatorRecord createOperatorRecord(LoginUser loginUser, HttpServletRequest request) {

        return null;
    }

    /**
     * 日志记录线程
     ***/
    private ExecutorService logThreadPool = null;

    public UserOperatorRecorder() {
        // 创建日志记录线程池
        logThreadPool = new ThreadPoolExecutor(2, Integer.parseInt(SysConfigParams.getConfig("logThreadNum")), 60L,
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    }

    @Override
    public void shutdownLogThreadPool(IOnShutdownLogThreadPool onShutdown) {
        logThreadPool.shutdown();
        int helper = 1;
        while (!logThreadPool.isShutdown() && helper < 60) {
            System.out.println("waiting for logThreadPool.shutdown..........");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            helper = helper + 1;
        }
        onShutdown.hasShutdown();
    }

    @Override
    public void record(final OperatorRecord record, final UrlInfo urlInfo) {
        try {
            logThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    boolean isLog = true;
                    Log log = null;
                    String opertorDesp = null;
                    String controllerName = urlInfo.getController().replaceFirst("/", "");
                    String actionName = urlInfo.getCmd();
                    record.setAction(actionName);
                    record.setController(controllerName);
                    /** 检查controllerName是否是配置到菜单中的，如果不是则记录到字典表 **/
                    if (SysConfigParams.isDevModel) {
                        Map<String, Object> param = new HashMap<String, Object>();
                        param.put("controller", controllerName);
                        try {
                            // typeid dvalue
                            int c = menuService.count(param);
                            if (c == 0) {
                                String typeId = "00000";
                                String dkey = "inner url";
                                String dvalue = controllerName;
                                param = new HashMap<String, Object>();
                                param.put("typeid", typeId);
                                param.put("dvalue", dvalue);
                                c = dictService.count(param);
                                if (c == 0) {
                                    Dict dict = new Dict();
                                    dict.setTypeid(typeId);
                                    dict.setDkey(dkey);
                                    dict.setDvalue(controllerName);
                                    dictService.insert(dict);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if ("login".equals(actionName)) {
                        opertorDesp = ":用户登录:1";
                    } else if ("logout".equals(actionName)) {
                        opertorDesp = ":用户退出系统:1";
                    } else if (actionName.contains("list") || actionName.contains("get")
                        || actionName.contains("query")) {
                        isLog = false;
                    }
                    if (isLog) {
                        try {
                            if (opertorDesp == null) {
                                opertorDesp = funcService.getOperatorDesp(controllerName, actionName);
                            }
                        } catch (Exception e) {
                            logger.error("getOperatorDesp {}", e);
                        }
                        if (StringUtils.isNoneEmpty(opertorDesp)) {
                            // menu_text:func_desc:is_log
                            String[] tmpArr = opertorDesp.split(":");
                            if (tmpArr.length == 3) {
                                isLog = "1".equals(tmpArr[2]);
                                if (isLog) {
                                    log = new Log();
                                    log.setCreateTime(new Date());
                                    log.setContent(tmpArr[1]);
                                    log.setCreateUser(record.getUserId());
                                    Exception ex = record.getException();
                                    if (ex != null) {
                                        log.setException(record.getException().getMessage());
                                        log.setOpstatus(0);
                                    } else {
                                        log.setOpstatus(1);
                                    }
                                    log.setMenuName(tmpArr[0]);
                                    log.setOperateData(record.getOpertorData());
                                    log.setOperateIp(record.getIp());
                                    log.setUrl(record.getUrl());
                                    try {
                                        logService.insert(log);
                                        String logDays = SysConfigParams.getConfig("logDays");
                                        if (StringUtil.isNotEmpty(logDays)) {
                                            Map<String, Object> prs = new HashMap<String, Object>();
                                            Date date = org.apache.commons.lang3.time.DateUtils.addDays(new Date(),
                                                -Integer.parseInt(logDays));
                                            prs.put("date", date);
                                            logService.deleteParam(prs);
                                        }
                                    } catch (Exception e) {
                                        logger.warn("{}", e);
                                    }
                                }
                            }
                        }
                    }
                }
            });
        } catch (Exception ex) {
            logger.error("logThreadPool  maybe is not enough thread to use ,current thread number is {} details:{}",
                SysConfigParams.getConfig("logThreadNum"), ex);
        }
    }

}
